package com.hz.tgb.common;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 身份证工具类
 *
 * @author hezhao on 2017年7月25日 下午3:02:59
 */
public class IDCardUtil {

    /**
     * 1、号码的结构 公民身份号码是特征组合码，由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为：六位数字地址码，八位数字出生日期码，三位数字顺序码和一位数字校验码。
     *
     * 2、地址码(前六位数） 表示编码对象常住户口所在县(市、旗、区)的行政区划代码，按GB/T2260的规定执行。
     *
     * 3、出生日期码（第七位至十四位） 表示编码对象出生的年、月、日，按GB/T7408的规定执行，年、月、日代码之间不用分隔符。
     *
     * 4、顺序码（第十五位至十七位） 表示在同一地址码所标识的区域范围内，对同年、同月、同日出生的人编定的顺序号，顺序码的奇数分配给男性，偶数分配给女性。
     *
     * 5、校验码（第十八位数）
     * （1）十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, ... , 16 ，先对前17位数字的权求和
     *      Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
     * （2）计算模 Y = mod(S, 11)
     * （3）通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9 8 7 6 5 4 3 2
     *
     */

    private IDCardUtil(){
        // 私有类构造方法
    }

    private static final Logger logger = LoggerFactory.getLogger(IDCardUtil.class);

    /** 中国公民身份证号码最小长度。 */
    private static final int CHINA_ID_MIN_LENGTH = 15;

    /** 中国公民身份证号码最大长度。 */
    private static final int CHINA_ID_MAX_LENGTH = 18;

    /** 省、直辖市代码表 */
    private static final String[] CITY_CODE = {"11", "12", "13", "14", "15",
            "21", "22", "23", "31", "32", "33", "34", "35", "36", "37", "41",
            "42", "43", "44", "45", "46", "50", "51", "52", "53", "54", "61",
            "62", "63", "64", "65", "71", "81", "82", "91"};

    /** 每位加权因子 */
    private static final int[] POWER = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    /** 第18位校检码 */
    private static final String[] VERIFY_CODE = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};

    /** 最低年限 */
    private static final int MIN = 1930;
    /** 大陆身份首两位数字对应省份 */
    private static final Map<String, String> CITY_CODES = new HashMap<>();
    /** 台湾身份首字母对应数字 */
    private static final Map<String, Integer> TW_FIRST_CODE = new HashMap<>();
    /** 香港身份首字母对应数字 */
    private static final Map<String, Integer> HK_FIRST_CODE = new HashMap<>();

    /** 天干 */
    private static final String[] STG = {"癸", "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "任"};
    /** 地支 */
    private static final String[] SDZ = {"亥", "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌"};

    private static final Pattern PATTERN_TW = Pattern.compile("^[a-zA-Z][0-9]{9}{1}");
    private static final Pattern PATTERN_MK = Pattern.compile("^[1|5|7][0-9]{6}\\(?[0-9A-Z]\\)?{1}");
    private static final Pattern PATTERN_HK = Pattern.compile("^[A-Z]{1,2}[0-9]{6}\\(?[0-9A]\\)?{1}");
    private static final Pattern PATTERN_NUM = Pattern.compile("^[0-9]*{1}");

    static {
        CITY_CODES.put("11", "北京");
        CITY_CODES.put("12", "天津");
        CITY_CODES.put("13", "河北");
        CITY_CODES.put("14", "山西");
        CITY_CODES.put("15", "内蒙古");
        CITY_CODES.put("21", "辽宁");
        CITY_CODES.put("22", "吉林");
        CITY_CODES.put("23", "黑龙江");
        CITY_CODES.put("31", "上海");
        CITY_CODES.put("32", "江苏");
        CITY_CODES.put("33", "浙江");
        CITY_CODES.put("34", "安徽");
        CITY_CODES.put("35", "福建");
        CITY_CODES.put("36", "江西");
        CITY_CODES.put("37", "山东");
        CITY_CODES.put("41", "河南");
        CITY_CODES.put("42", "湖北");
        CITY_CODES.put("43", "湖南");
        CITY_CODES.put("44", "广东");
        CITY_CODES.put("45", "广西");
        CITY_CODES.put("46", "海南");
        CITY_CODES.put("50", "重庆");
        CITY_CODES.put("51", "四川");
        CITY_CODES.put("52", "贵州");
        CITY_CODES.put("53", "云南");
        CITY_CODES.put("54", "西藏");
        CITY_CODES.put("61", "陕西");
        CITY_CODES.put("62", "甘肃");
        CITY_CODES.put("63", "青海");
        CITY_CODES.put("64", "宁夏");
        CITY_CODES.put("65", "新疆");
        CITY_CODES.put("71", "台湾");
        CITY_CODES.put("81", "香港");
        CITY_CODES.put("82", "澳门");
        CITY_CODES.put("91", "国外");
        TW_FIRST_CODE.put("A", 10);
        TW_FIRST_CODE.put("B", 11);
        TW_FIRST_CODE.put("C", 12);
        TW_FIRST_CODE.put("D", 13);
        TW_FIRST_CODE.put("E", 14);
        TW_FIRST_CODE.put("F", 15);
        TW_FIRST_CODE.put("G", 16);
        TW_FIRST_CODE.put("H", 17);
        TW_FIRST_CODE.put("J", 18);
        TW_FIRST_CODE.put("K", 19);
        TW_FIRST_CODE.put("L", 20);
        TW_FIRST_CODE.put("M", 21);
        TW_FIRST_CODE.put("N", 22);
        TW_FIRST_CODE.put("P", 23);
        TW_FIRST_CODE.put("Q", 24);
        TW_FIRST_CODE.put("R", 25);
        TW_FIRST_CODE.put("S", 26);
        TW_FIRST_CODE.put("T", 27);
        TW_FIRST_CODE.put("U", 28);
        TW_FIRST_CODE.put("V", 29);
        TW_FIRST_CODE.put("X", 30);
        TW_FIRST_CODE.put("Y", 31);
        TW_FIRST_CODE.put("W", 32);
        TW_FIRST_CODE.put("Z", 33);
        TW_FIRST_CODE.put("I", 34);
        TW_FIRST_CODE.put("O", 35);
        HK_FIRST_CODE.put("A", 1);
        HK_FIRST_CODE.put("B", 2);
        HK_FIRST_CODE.put("C", 3);
        HK_FIRST_CODE.put("R", 18);
        HK_FIRST_CODE.put("U", 21);
        HK_FIRST_CODE.put("Z", 26);
        HK_FIRST_CODE.put("X", 24);
        HK_FIRST_CODE.put("W", 23);
        HK_FIRST_CODE.put("O", 15);
        HK_FIRST_CODE.put("N", 14);
    }

    /**
     * 将15位身份证号码转换为18位
     *
     * @param idCard
     *            15位身份编码
     * @return 18位身份编码
     */
    public static String convert15CardTo18(String idCard) {
        String idCard18;
        if (idCard.length() != CHINA_ID_MIN_LENGTH) {
            return null;
        }
        if (isNum(idCard)) {
            // 获取出生年月日
            String birthday = idCard.substring(6, 12);
            Date birthDate = null;
            try {
                birthDate = new SimpleDateFormat("yyMMdd").parse(birthday);
            } catch (ParseException e) {
                logger.error(e.toString(),e);
            }
            Calendar cal = Calendar.getInstance();
            if (birthDate != null) {
                cal.setTime(birthDate);
            }
            // 获取出生年(完全表现形式,如：2010)
            String sYear = String.valueOf(cal.get(Calendar.YEAR));
            idCard18 = idCard.substring(0, 6) + sYear + idCard.substring(8);
            // 转换字符数组
            char[] cArr = idCard18.toCharArray();
            if (ArrayUtils.isNotEmpty(cArr)) {
                int[] iCard = converCharToInt(cArr);
                int iSum17 = getPowerSum(iCard);
                // 获取校验位
                String sVal = getCheckCode18(iSum17);
                if (sVal.length() > 0) {
                    idCard18 += sVal;
                } else {
                    return null;
                }
            }
        } else {
            return null;
        }
        return idCard18;
    }

    /**
     * 根据正则校验18位身份证
     * @param idCard 身份编码
     * @return
     */
    public static boolean validateIDCardByRegex(String idCard) {
        String curYear = "" + Calendar.getInstance().get(Calendar.YEAR);
        int y3 = Integer.parseInt(curYear.substring(2, 3));
        int y4 = Integer.parseInt(curYear.substring(3, 4));
        // 43 0103 1973 0 9 30 051 9
        return idCard.matches("^(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|71|8[1-2])\\d{4}(19\\d{2}|20([0-" + (y3 - 1) + "][0-9]|" + y3 + "[0-" + y4
                + "]))(((0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])))\\d{3}([0-9]|x|X)$");
        // 44 1825 1988 0 7 1 3 003 4
    }


    /**
     * 验证身份证是否合法
     */
    public static boolean validateIdCard(String idCard) {
        String card = idCard.trim();
        if (validateIdCard18(card)) {
            return true;
        }
        if (validateIdCard15(card)) {
            return true;
        }
        String[] cardVal = validateIdCard10(card);
        if (cardVal != null) {
            if ("true".equals(cardVal[2])) {
                return true;
            }
        }
        return false;
    }

    /**
     * 验证18位身份编码是否合法
     *
     * @param idCard
     *            身份编码
     * @return 是否合法
     */
    public static boolean validateIdCard18(String idCard) {
        boolean bTrue = false;
        if (idCard.length() == CHINA_ID_MAX_LENGTH) {
            // 前17位
            String code17 = idCard.substring(0, 17);
            // 第18位
            String code18 = idCard.substring(17, CHINA_ID_MAX_LENGTH);
            if (isNum(code17)) {
                char[] cArr = code17.toCharArray();
                if (ArrayUtils.isNotEmpty(cArr)) {
                    int[] iCard = converCharToInt(cArr);
                    int iSum17 = getPowerSum(iCard);
                    // 获取校验位
                    String val = getCheckCode18(iSum17);
                    if (val.length() > 0) {
                        if (val.equalsIgnoreCase(code18)) {
                            bTrue = true;
                        }
                    }
                }
            }
        }
        //校验通过 且 正则校验通过 且 可以获取到省份信息
        return bTrue && validateIDCardByRegex(idCard) && getProvinceByIdCard(idCard)!=null;
    }

    /**
     * 验证15位身份编码是否合法
     *
     * @param idCard
     *            身份编码
     * @return 是否合法
     */
    public static boolean validateIdCard15(String idCard) {
        if (idCard.length() != CHINA_ID_MIN_LENGTH) {
            return false;
        }
        if (isNum(idCard)) {
            String proCode = idCard.substring(0, 2);
            if (CITY_CODES.get(proCode) == null) {
                return false;
            }
            String birthCode = idCard.substring(6, 12);
            Date birthDate = null;
            try {
                birthDate = new SimpleDateFormat("yy").parse(birthCode
                        .substring(0, 2));
            } catch (ParseException e) {
                logger.error(e.toString(),e);
            }
            Calendar cal = Calendar.getInstance();
            if (birthDate != null) {
                cal.setTime(birthDate);
            }
            if (!validateDate(cal.get(Calendar.YEAR),
                    Integer.parseInt(birthCode.substring(2, 4)),
                    Integer.parseInt(birthCode.substring(4, 6)))) {
                return false;
            }
        } else {
            return false;
        }
        return true;
    }

    /**
     * 验证10位身份编码是否合法
     *
     * @param idCard
     *            身份编码
     * @return 身份证信息数组
     *         <p>
     *         [0] - 台湾、澳门、香港 [1] - 性别(男M,女F,未知N) [2] - 是否合法(合法true,不合法false)
     *         若不是身份证件号码则返回null
     *         </p>
     */
    public static String[] validateIdCard10(String idCard) {
        String[] info = new String[3];
        String card = idCard.replaceAll("[\\(|\\)]", "");
        if (card.length() != 8 && card.length() != 9 && idCard.length() != 10) {
            return null;
        }
        // 台湾
        if (PATTERN_TW.matcher(idCard).matches()) {
            info[0] = "台湾";
//            System.out.println("11111");
            String char2 = idCard.substring(1, 2);
            if ("1".equals(char2)) {
                info[1] = "M";
//                System.out.println("MMMMMMM");
            } else if ("2".equals(char2)) {
                info[1] = "F";
//                System.out.println("FFFFFFF");
            } else {
                info[1] = "N";
                info[2] = "false";
//                System.out.println("NNNN");
                return info;
            }
            info[2] = validateTWCard(idCard) ? "true" : "false";
        // 澳门
        } else if (PATTERN_MK.matcher(idCard).matches()) {
            info[0] = "澳门";
            info[1] = "N";
            // TODO
        // 香港
        } else if (PATTERN_HK.matcher(idCard).matches()) {
            info[0] = "香港";
            info[1] = "N";
            info[2] = validateHKCard(idCard) ? "true" : "false";
        } else {
            return null;
        }
        return info;
    }

    /**
     * 验证台湾身份证号码
     *
     * @param idCard
     *            身份证号码
     * @return 验证码是否符合
     */
    public static boolean validateTWCard(String idCard) {
        String start = idCard.substring(0, 1);
        String mid = idCard.substring(1, 9);
        String end = idCard.substring(9, 10);
        Integer iStart = TW_FIRST_CODE.get(start);
        Integer sum = iStart / 10 + (iStart % 10) * 9;
        char[] chars = mid.toCharArray();
        Integer iflag = 8;
        for (char c : chars) {
            sum = sum + Integer.parseInt(c + "") * iflag;
            iflag--;
        }
        return (sum % 10 == 0 ? 0 : (10 - sum % 10)) == Integer.parseInt(end);
    }

    /**
     * 验证香港身份证号码(存在Bug，部份特殊身份证无法检查)
     * <p>
     * 身份证前2位为英文字符，如果只出现一个英文字符则表示第一位是空格，对应数字58 前2位英文字符A-Z分别对应数字10-35
     * 最后一位校验码为0-9的数字加上字符"A"，"A"代表10
     * </p>
     * <p>
     * 将身份证号码全部转换为数字，分别对应乘9-1相加的总和，整除11则证件号码有效
     * </p>
     *
     * @param idCard
     *            身份证号码
     * @return 验证码是否符合
     */
    public static boolean validateHKCard(String idCard) {
        String card = idCard.replaceAll("[\\(|\\)]", "");
        int sum;
        if (card.length() == 9) {
            sum = (card.substring(0, 1).toUpperCase().toCharArray()[0] - 55) * 9
                    + (card.substring(1, 2).toUpperCase().toCharArray()[0] - 55) * 8;
            card = card.substring(1, 9);
        } else {
            sum = 522 + (card.substring(0, 1).toUpperCase().toCharArray()[0] - 55) * 8;
        }
        String mid = card.substring(1, 7);
        String end = card.substring(7, 8);
        char[] chars = mid.toCharArray();
        Integer flag = 7;
        for (char c : chars) {
            sum = sum + Integer.parseInt(c + "") * flag;
            flag--;
        }
        if ("A".equals(end.toUpperCase())) {
            sum = sum + 10;
        } else {
            sum = sum + Integer.parseInt(end);
        }
        return sum % 11 == 0;
    }

    /**
     * 根据身份编号获取年龄
     *
     * @param idNo 身份编号
     *
     * @return 年龄
     */
    public static int getAgeByIdCard(String idNo) {
        try {
            Calendar currentDate = Calendar.getInstance();

            int bornYear = Integer.parseInt(idNo.substring(6, 10));
            int bornMonth = Integer.parseInt(idNo.substring(10, 12));
            int bornDay = Integer.parseInt(idNo.substring(12, 14));

            int currentYear = currentDate.get(Calendar.YEAR);
            int currentMonth = currentDate.get(Calendar.MONTH) + 1;
            int currentDay = currentDate.get(Calendar.DATE);

            int age = currentYear - bornYear;
            if (bornMonth  > currentMonth ||
                    (bornMonth == currentMonth && bornDay > currentDay)) {
                age--;
            }
            return age;
        } catch (Throwable e) {
            String errMsg = String.format("年龄计算失败, idNo:%s", idNo);
            logger.error(errMsg);
            throw new RuntimeException(errMsg, e);
        }

    }

    /**
     * 根据身份编号获取生日
     *
     * @param idCard
     *            身份编号
     * @return 生日(yyyyMMdd)
     */
    public static String getBirthByIdCard(String idCard) {
        Integer len = idCard.length();
        if (len < CHINA_ID_MIN_LENGTH) {
            return null;
        } else if (len == CHINA_ID_MIN_LENGTH) {
            idCard = convert15CardTo18(idCard);
        }
        return StringUtils.substring(idCard, 6, 14);
    }

    /**
     * 根据身份编号获取生日
     *
     * @param idCard
     *            身份编号
     * @return 生日(yyyy-MM-dd)
     */
    public static String getBirthFormatByIdCard(String idCard) {
        Integer len = idCard.length();
        if (len < CHINA_ID_MIN_LENGTH) {
            return null;
        } else if (len == CHINA_ID_MIN_LENGTH) {
            idCard = convert15CardTo18(idCard);
        }
        return StringUtils.substring(idCard, 6, 10) +
                "-" + StringUtils.substring(idCard, 10, 12) +
                "-" + StringUtils.substring(idCard, 12, 14);
    }

    /**
     * 根据身份编号获取生日年
     *
     * @param idCard
     *            身份编号
     * @return 生日(yyyy)
     */
    public static Short getYearByIdCard(String idCard) {
        Integer len = idCard.length();
        if (len < CHINA_ID_MIN_LENGTH) {
            return null;
        } else if (len == CHINA_ID_MIN_LENGTH) {
            idCard = convert15CardTo18(idCard);
        }
        return Short.valueOf(Objects.requireNonNull(StringUtils.substring(idCard, 6, 10)));
    }

    /**
     * 根据身份编号获取生日月
     *
     * @param idCard
     *            身份编号
     * @return 生日(MM)
     */
    public static Short getMonthByIdCard(String idCard) {
        Integer len = idCard.length();
        if (len < CHINA_ID_MIN_LENGTH) {
            return null;
        } else if (len == CHINA_ID_MIN_LENGTH) {
            idCard = convert15CardTo18(idCard);
        }
        return Short.valueOf(Objects.requireNonNull(StringUtils.substring(idCard, 10, 12)));
    }

    /**
     * 根据身份编号获取生日天
     *
     * @param idCard
     *            身份编号
     * @return 生日(dd)
     */
    public static Short getDateByIdCard(String idCard) {
        Integer len = idCard.length();
        if (len < CHINA_ID_MIN_LENGTH) {
            return null;
        } else if (len == CHINA_ID_MIN_LENGTH) {
            idCard = convert15CardTo18(idCard);
        }
        return Short.valueOf(Objects.requireNonNull(StringUtils.substring(idCard, 12, 14)));
    }

    /**
     * 根据身份编号获取性别
     *
     * @param idCard
     *            身份编号
     * @return 性别(M-男，F-女，N-未知)
     */
    public static String getGenderByIdCard(String idCard) {
        String sGender;
        if (idCard.length() == CHINA_ID_MIN_LENGTH) {
            idCard = convert15CardTo18(idCard);
        }
        String sCardNum = StringUtils.substring(idCard, 16, 17);

        // 出错，不是整数
        if (!isNum(sCardNum)) {
            String errMsg = String.format("性别计算失败, idNo:%s", idCard);
            logger.error(errMsg);
            throw new RuntimeException(errMsg);
        }

        if (Integer.parseInt(sCardNum) % 2 != 0) {
            sGender = "M";
        } else {
            sGender = "F";
        }
        return sGender;
    }

    /**
     * 根据身份编号获取户籍省份
     *
     * @param idCard
     *            身份编码
     * @return 省级编码。
     */
    public static String getProvinceByIdCard(String idCard) {
        int len = idCard.length();
        String sProvinceNum = "";
        if (len == CHINA_ID_MIN_LENGTH || len == CHINA_ID_MAX_LENGTH) {
            sProvinceNum = idCard.substring(0, 2);
        }
        return CITY_CODES.get(sProvinceNum);
    }

    /**
     *根据身份证号，自动获取对应的星座
     *
     * @param idCard
     *            身份证号码
     * @return 星座
     */
    public static String getConstellationById(String idCard) {
        if (!validateIdCard(idCard)) {
            return "";
        }
        Short monthByIdCard = IDCardUtil.getMonthByIdCard(idCard);
        Short dateByIdCard = IDCardUtil.getDateByIdCard(idCard);
        if (monthByIdCard == null || dateByIdCard == null) {
            return "";
        }

        int month = monthByIdCard;
        int day = dateByIdCard;
        String strValue = "";

        if ((month == 1 && day >= 20) || (month == 2 && day <= 18)) {
            strValue = "水瓶座";
        } else if ((month == 2 && day >= 19) || (month == 3 && day <= 20)) {
            strValue = "双鱼座";
        } else if ((month == 3 && day > 20) || (month == 4 && day <= 19)) {
            strValue = "白羊座";
        } else if ((month == 4 && day >= 20) || (month == 5 && day <= 20)) {
            strValue = "金牛座";
        } else if ((month == 5 && day >= 21) || (month == 6 && day <= 21)) {
            strValue = "双子座";
        } else if ((month == 6 && day > 21) || (month == 7 && day <= 22)) {
            strValue = "巨蟹座";
        } else if ((month == 7 && day > 22) || (month == 8 && day <= 22)) {
            strValue = "狮子座";
        } else if ((month == 8 && day >= 23) || (month == 9 && day <= 22)) {
            strValue = "处女座";
        } else if ((month == 9 && day >= 23) || (month == 10 && day <= 23)) {
            strValue = "天秤座";
        } else if ((month == 10 && day > 23) || (month == 11 && day <= 22)) {
            strValue = "天蝎座";
        } else if ((month == 11 && day > 22) || (month == 12 && day <= 21)) {
            strValue = "射手座";
        } else if ((month == 12 && day > 21) || (month == 1 && day <= 19)) {
            strValue = "魔羯座";
        }

        return strValue;
    }


    /**
     *根据身份证号，自动获取对应的生肖
     *
     * @param idCard
     *            身份证号码
     * @return 生肖
     */
    public static String getZodiacById(String idCard) { // 根据身份证号，自动返回对应的生肖
        if (!validateIdCard(idCard)) {
            return "";
        }

        String[] ssx = {"猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗"};
        Short yearByIdCard = IDCardUtil.getYearByIdCard(idCard);
        if (yearByIdCard == null) {
            return "";
        }

        int year = yearByIdCard;
        int end = 3;
        int x = (year - end) % 12;
        return ssx[x];
    }


    /**
     *根据身份证号，自动获取对应的天干地支
     *
     * @param idCard
     *            身份证号码
     * @return 天干地支
     */
    public static String getChineseEraById(String idCard) {
        if (!validateIdCard(idCard)) {
            return "";
        }

        Short yearByIdCard = IDCardUtil.getYearByIdCard(idCard);
        if (yearByIdCard == null) {
            return "";
        }

        int year = yearByIdCard;
        int i = (year - 3) % 10;
        int j = (year - 3) % 12;
        return STG[i] + SDZ[j];
    }

    /**
     * 将字符数组转换成数字数组
     *
     * @param ca
     *            字符数组
     * @return 数字数组
     */
    private static int[] converCharToInt(char[] ca) {
        int len = ca.length;
        int[] iArr = new int[len];
        try {
            for (int i = 0; i < len; i++) {
                iArr[i] = Integer.parseInt(String.valueOf(ca[i]));
            }
        } catch (NumberFormatException e) {
            logger.error(e.toString(),e);
        }
        return iArr;
    }

    /**
     * 数字验证
     *
     * @param val
     * @return 提取的数字。
     */
    private static boolean isNum(String val) {
        return val != null && !"".equals(val) && PATTERN_NUM.matcher(val).matches();
    }

    /**
     * 验证小于当前日期 是否有效
     *
     * @param iYear
     *            待验证日期(年)
     * @param iMonth
     *            待验证日期(月 1-12)
     * @param iDate
     *            待验证日期(日)
     * @return 是否有效
     */
    private static boolean validateDate(int iYear, int iMonth, int iDate) {
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR);
        int datePerMonth;
        if (iYear < MIN || iYear >= year) {
            return false;
        }
        if (iMonth < 1 || iMonth > 12) {
            return false;
        }
        switch (iMonth) {
            case 4:
            case 6:
            case 9:
            case 11:
                datePerMonth = 30;
                break;
            case 2:
                boolean dm = (iYear % 4 == 0 && iYear % 100 != 0 || iYear % 400 == 0) && iYear > MIN;
                datePerMonth = dm ? 29 : 28;
                break;
            default:
                datePerMonth = 31;
        }
        return (iDate >= 1) && (iDate <= datePerMonth);
    }

    /**
     * 将身份证的每位和对应位的加权因子相乘之后，再得到和值
     *
     * @param iArr
     * @return 身份证编码。
     */
    private static int getPowerSum(int[] iArr) {
        int iSum = 0;
        if (POWER.length == iArr.length) {
            for (int i = 0; i < iArr.length; i++) {
                for (int j = 0; j < POWER.length; j++) {
                    if (i == j) {
                        iSum = iSum + iArr[i] * POWER[j];
                    }
                }
            }
        }
        return iSum;
    }

    /**
     * 将power和值与11取模获得余数进行校验码判断
     *
     * @param iSum
     * @return 校验位
     */
    private static String getCheckCode18(int iSum) {
        int modValue = iSum % 11;
        return VERIFY_CODE[modValue];
    }

    public static void main(String[] args) {
        String idCard = "xxxxxxxxxxxxxxxxxx";
        System.out.println(IDCardUtil.validateIdCard(idCard));
        System.out.println(IDCardUtil.getGenderByIdCard(idCard));
        System.out.println(IDCardUtil.getAgeByIdCard(idCard));
        System.out.println(IDCardUtil.getBirthByIdCard(idCard));
        System.out.println(IDCardUtil.getBirthFormatByIdCard(idCard));
        System.out.println(IDCardUtil.getMonthByIdCard(idCard));
        System.out.println(IDCardUtil.getDateByIdCard(idCard));
        System.out.println(IDCardUtil.getConstellationById(idCard));
        System.out.println(IDCardUtil.getZodiacById(idCard));
        System.out.println(IDCardUtil.getChineseEraById(idCard));
        System.out.println(IDCardUtil.getProvinceByIdCard(idCard));
    }
}